//przykladowa klasa z przykladem uzycia oraz komentarzami w stylu doxygen

#ifndef COMPLEX_H
#define COMPLEX_H

/*!
 * \file sample.h
 * \brief przykladowa klasa
 * \details przykladowa klasa do podstawowej obslugi liczb urojonych
 * \version 0.0.1
 * \author juszczyk.pawel@gmail.com
 * \date 7/8/2012
 */

#include <iosfwd>
#include <algorithm>
#include <string>
#include <sstream>

/*!
 * \namespace przestrzen nazw zwiazana z operacjami matematycznymi
 */
namespace Math {

    /*!
     * \class klasa do obslugi liczb urojonych
     */
    class Complex {
        /*!
         * \var real czesc rzeczywista liczby
         */
        double real;
        /*!
         * \var imaginary czesc urojona
         */
        double imaginary;
        public:
           /*!
            * \fn explicit Complex()
            * \brief konstruktor bezargumentowy
            */
           explicit Complex() : real(0.0), imaginary(0.0) {}
           /*!
            * \fn explicit Complex(double r, double i = 0.0)
            * \brief konstruktor
            * \param r double czesc rzeczywista
            * \param i double czesc urojona
            */
           explicit Complex(double r, double i = 0.0) : real(r), imaginary(i) {}
           /*!
            * \fn Complex(const Complex& lhs)
            * \brief konstruktor kopiujacy
            * \param lhs const Complex& 
            */
           Complex(const Complex& lhs) : real(lhs.real), imaginary(lhs.imaginary) {}
           /*!
            * \fn operator=(const Complex& lhs)
            * \brief operator przypisania
            * \param lhs const Complex&
            * \return referencja na obiekt na ktorym zostalo wykonane przypisanie
            */
           Complex& operator=(const Complex& lhs) {
               Complex temp(lhs);
               swap(temp);
               return *this;
           }
           /*!
            * \fn swap(Complex& lhs)
            * \brief metoda zamieniajaca dwa obiekty
            * \param lhs Complex& obiekt, ktory bedzie zamieniony
            * \return void
            */
           void swap(Complex& lhs) throw() {
               //wykorzystujemy funkcje swap z biblioteki standardowej
               using std::swap;
               swap(real, lhs.real);
               swap(imaginary, lhs.imaginary);
           }
           /*!
            * \fn operator+(const Complex& lhs)
            * \brief operator skroconego dodawania
            * \param lhs const Complex&
            * \return Complex& referencja na obiekt na ktorym zostalo wykonane przypisanie
            */
           Complex& operator+=(const Complex& lhs) {
               real += lhs.real;
               imaginary += lhs.imaginary;
               return *this;
           }
           /*!
            * \fn operator++()
            * \brief operator preinkrementacji
            * \return Complex& referencja na obiekt na ktorym zostala wykonana preinkrementacja
            */
           Complex& operator++() {
               ++real;
               return *this;
           }
           /*!
            * \fn operator++(int)
            * \brief operator postinkrementacji
            * \details zaimplementowany z wykorzystaniem operatora preinkrementacji
            * \param int ignorowany parametr
            * \return const Complex staly obiekt utworzony w wyniku postinkrementacji
            */
           const Complex operator++(int) {
               Complex old(*this);
               operator++();
               return old;
           }
           /*!
            * \fn toString() const
            * \brief metoda zwaracajaca string reprezentujacy obiekt
            * \return std::string
            */
           std::string toString() const {
               std::ostringstream ss;
               ss << real << "+" << imaginary << "j";
               return ss.str();
           }
    };

    /*!
     * \fn operator+(const Complex& lhs, const Complex& rhs)
     * \brief operator dodawania
     * \details zaimplementowany z wykorzystaniem operatora skrocenego dodawania
     * \param lhs wartosc po lewej stronie operatora dodawania
     * \param rhs wartosc po prawej stronie operatora dodawania
     * \return const Complex staly obiekt utworzony w wyniku dodawania
     */
    const Complex operator+(const Complex& lhs, const Complex& rhs) {
        Complex temp(lhs);
        temp += rhs;
        return temp;
    }

    /*
     * \fn operator<<(std::ostream& os, const Complex& c)
     * \brief operator strumieniowy dla klasy Complex
     * \details wykorzystuje metode toString
     * \param os std::ostream& referencja na strumien wyjsciowy
     * \param c const Complex& refencja na obiekt
     * \return std::ostream& referencja na strumien wyjsciowy
     */
    std::ostream& operator<<(std::ostream& os, const Complex& c) {
        return os << c.toString();
    }

    /*!
     * \fn swap(Complex& a, Complex& b)
     * \brief funkcja swapujaca dwa obiekty
     * \details wykorzystuje metode swap
     * \return void
     */
    void swap(Complex& a, Complex& b) throw() {
        a.swap(b);
    }

}

namespace std {
    /*!
     * \fn template<> swap<Math::Complex>(Math::Complex& a, Math::Complex& b)
     * \brief pelna specjalizacje funkcji swap dla klasy Complex
     * \details wykorzystuje metode swap z klasy Complex
     * \param a Math::Complex&
     * \param b Math::Complex&
     * \return void
     */
    template<>
    void swap<Math::Complex>(Math::Complex& a, Math::Complex& b) {
        a.swap(b);
    }
}

#endif //COMPLEX_H
